package yu.ac.bg.etf.kdp.klijent;

import java.io.*;
import java.net.*;
import java.util.*;
import yu.ac.bg.etf.kdp.klase.*;

public class Client {

	private String command;
	private String inMatrix;
	private String data;
	private String result;
	
	private String serverHost;
	private int serverPort;

	public Client() {
		this("localhost", 2001);
	}

	public Client(String serverHost, int serverPort) {
		this.serverHost = serverHost;
		this.serverPort = serverPort;
		try {
			FileInputStream f = new FileInputStream("job_data.txt");
			f.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			try {
				FileOutputStream f = new FileOutputStream("job_data.txt", true);
			} catch (FileNotFoundException e1) {
				// TODO Auto-generated catch block
				System.out.println("Unable to acces job data file..");
			}
		} catch (IOException e1) {
			System.out.println("Unable to acces job data file..");
		}
	}
	
	public synchronized int sendJob(String comFileName) {
		int jobId = -1;
		parseJobFile(comFileName);
		if (command == null) {
			System.out.println("Bad command file format..");
			return jobId;
		} else {
			try {
				FileInputStream f = new FileInputStream(inMatrix);
				f.close();
				FileInputStream f1;
				if (data != null) {
					f1 = new FileInputStream(data);
					f1.close();
				}
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				return jobId;
			} catch (IOException io) {
				//
			}
		}
		try {
			// kacimo se na server
			Socket clientSocket = new Socket(serverHost,serverPort);
			clientSocket.setSoTimeout(10000);
			// inicijalizujemo tokove podataka
			OutputStream os = clientSocket.getOutputStream();
			InputStream is = clientSocket.getInputStream();
			ObjectOutputStream outo = new ObjectOutputStream(os);
			outo.flush();
			ObjectInputStream ino = new ObjectInputStream(is);
			BufferedOutputStream bos = new BufferedOutputStream(os);
			BufferedInputStream bis = new BufferedInputStream(is);
			// protokol komunikacije
			outo.writeObject(new MsgTxt("cliRequest"));
			outo.flush();
			outo.writeObject(new MsgTxt("newJob"));
			outo.flush();
			// saljemo vrstu posla koji treba da se odradi
			outo.writeObject(new MsgTxt(command));
			outo.flush();
			// saljemo ime datoteke u koju treba smestiti rezultate
			outo.writeObject(new MsgTxt(result));
			outo.flush();
			// saljemo matricu nad kojom se obavlja operacija a.txt
			System.out.println("Sending input matrix..");
			FileTransfer.sendFile(outo, inMatrix);
			System.out.println("Input matrix sent..");
			// saljemo vektor rezultata/promenljivih ako ga ima b.txt
			if (data != null) {
				outo.writeObject(new MsgTxt("sendingB"));
				outo.flush();
				System.out.println("Sending result/variable vector..");
				FileTransfer.sendFile(outo, data);
				System.out.println("Vector sent..");
			} else {
				outo.writeObject(new MsgTxt("notSendingB"));
				outo.flush();
			}
			// primamo identifikator posla koji smo zapoceli
			Job job = (Job)ino.readObject();
			jobId = job.getId();
			// zatvaramo tokove podataka
			outo.close();
			ino.close();
			clientSocket.close();
		} catch (UnknownHostException e2) {
			System.out.println("Unknown host..");
			return jobId;
		} catch (IOException e) {
			// TODO: handle exception
			System.out.println("Connection could not be established..");
			return jobId;
		} catch (ClassNotFoundException e1) {
			System.out.println("Class not found..");
			System.exit(1);
		}
		System.out.println("Job sent to server..");
		try {
			FileOutputStream file = new FileOutputStream("job_data.txt",true);
			PrintWriter data = new PrintWriter(file);
			data.println("Job "+jobId);
			data.close();
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			System.out.println("Job data file could not be found..");
		}
		return jobId;
	}

	private void parseJobFile(String comFileName) {
		ArrayList list = null;
		try {
			list = FileParser.parseDelimitedFile(comFileName, "=");
			try {
				// citamo prvu liniju komandnog fajla
				String[] line = (String[]) list.remove(0);
				if (line.length != 2 || !line[0].equals("command")) {
					command = null;
					return;
				} else {
					command = new String(line[1]);
				}
				if (!command.equals("solve") && !command.equals("calculate")
						&& !command.equals("getLUDecomposition")
						&& !command.equals("getEigenvalueDecomposition")
						&& !command.equals("getLUDecomposition")
						&& !command.equals("getInverseMatrix")
						&& !command.equals("getMatrixDeterminant")) {
					command = null;
					return;
				}
				// citamo drugu liniju komandnog fajla
				line = (String[]) list.remove(0);
				if (line.length != 2 || !line[0].equals("inMatrix")) {
					command = null;
					return;
				} else {
					inMatrix = new String(line[1]);
				}
				// citamo trecu liniju komandnog fajla
				line = (String[]) list.remove(0);
				if (line.length != 2 || !line[0].equals("data")
						&& !line[0].equals("result")) {
					command = null;
					return;
				} else if (line[0].equals("data")) {
					data = new String(line[1]);
					// citamo cetvrtu liniju komandnog fajla
					line = (String[]) list.remove(0);
					if (line.length != 2 || !line[0].equals("result")) {
						command = null;
						return;
					} else {
						result = new String(line[1]);
					}
				} else {
					result = new String(line[1]);
					data = null;
				}
			} catch (Exception e) {
				System.out.println("Bad command file..");
			}
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			System.out.println("Command file error..");
			command = null;
		}
		

	}

	public synchronized void getResults(int jobId) {
		try {
			// kacimo se na server
			Socket clientSocket = new Socket(serverHost, serverPort);
			// inicijalizujemo tokove podataka
			ObjectOutputStream outo = new ObjectOutputStream(clientSocket.getOutputStream());
			ObjectInputStream ino = new ObjectInputStream(clientSocket.getInputStream());
			// protokol komunikacije
			outo.writeObject(new MsgTxt("cliRequest"));
			outo.flush();
			outo.writeObject(new MsgTxt("getResults"));
			outo.flush();
			outo.writeObject(new MsgTxt(""+jobId));
			outo.flush();
			// primamo potvrdu da postoji posao koji smo zadali na serveru
			Msg msg;
			try {
				msg = (Msg) ino.readObject();
				String ack = (String) msg.getBody();
				if (ack.equals("jobExists")) {
					// treba da vidimo da li je posao odradjen
					msg = (Msg) ino.readObject();
					String status = (String) msg.getBody();
					if (status.equals("jobDone")) {
						// primamo posao
						Job job = (Job)ino.readObject();
						// primamo matricu sa rezultatima x.txt
						System.out.println("Recieving result matrix (x.txt)..");
						FileTransfer.recieveFile(ino, job.getResults());
						System.out.println("Result matrix recieved (x.txt)..");
					} else if (status.equals("jobAborted")
							|| status.equals("jobFailed")) {
						System.out.println("Job failed or aborted by user..");
					}
				} else if (ack.equals("jobNotExists")) {
					System.out
							.println("Results not recieved because job is not on server..");
				} else {
					System.out.println("Bad protocol message..");
					System.exit(1);
				}
				try {
					BufferedReader data = new BufferedReader(new InputStreamReader(new FileInputStream("job_data.txt")));
					LinkedList l = new LinkedList();
					String line = data.readLine();
					while (line != null) {
						l.add(line);
						line = data.readLine();
					}
					FileOutputStream file = new FileOutputStream("job_data.txt",false);
					PrintWriter data1 = new PrintWriter(file);
					for (int i = 0;i < l.size();i++) {
						line = (String)l.get(i);
						String[] ar = line.split(" ");
						if (Integer.parseInt(ar[1]) != jobId) data1.write(line+"\n");
					}
					data1.close();
					data.close();
				} catch (FileNotFoundException e1) {
					// TODO Auto-generated catch block
					System.out.println("Job data file could not be found..");
				}
			} catch (ClassNotFoundException e1) {
				// TODO Auto-generated catch block
				System.out.println("Class not found..");
				System.exit(1);
			}

		} catch (IOException e) {
			// TODO: handle exception
			System.out.println("Connection broken..");
			System.exit(1);
		}

	}
	
	public synchronized void abortJob (int jobId) {
		try {
			// kacimo se na server
			Socket clientSocket = new Socket(serverHost, serverPort);
			// inicijalizujemo tokove podataka
			ObjectOutputStream outo = new ObjectOutputStream(clientSocket.getOutputStream());
			ObjectInputStream ino = new ObjectInputStream(clientSocket.getInputStream());
			// protokol komunikacije
			outo.writeObject(new MsgTxt("cliRequest"));
			outo.flush();
			outo.writeObject(new MsgTxt("abortJob"));
			outo.flush();
			outo.writeObject(new MsgTxt(""+jobId));
			outo.flush();
			// primamo potvrdu da postoji posao koji smo zadali na serveru
			Msg msg;
			try {
				msg = (Msg) ino.readObject();
				String ack = (String) msg.getBody();
				if (ack.equals("jobExists")) {
					// treba da vidimo da li je posao unisten
					msg = (Msg) ino.readObject();
					String status = (String) msg.getBody();
					if (status.equals("jobAborted")) {
						try {
							BufferedReader data = new BufferedReader(new InputStreamReader(new FileInputStream("job_data.txt")));
							LinkedList l = new LinkedList();
							String line = data.readLine();
							while (line != null) {
								l.add(line);
								line = data.readLine();
							}
							FileOutputStream file = new FileOutputStream("job_data.txt",false);
							PrintWriter data1 = new PrintWriter(file);
							for (int i = 0;i < l.size();i++) {
								line = (String)l.get(i);
								String[] ar = line.split(" ");
								if (Integer.parseInt(ar[1]) != jobId) data1.write(line+"\n");
							}
							data1.close();
							data.close();
						} catch (FileNotFoundException e1) {
							// TODO Auto-generated catch block
							System.out.println("Job data file could not be found..");
						}
					} else {
						System.out.println("Bad protocol message..");
						System.exit(1);
					}
				} else if (ack.equals("jobNotExists")) {
					System.out
							.println("Job not aborted because job is not on server..");
				} else {
					System.out.println("Bad protocol message..");
					System.exit(1);
				}
			} catch (ClassNotFoundException e1) {
				// TODO Auto-generated catch block
				System.out.println("Class not found..");
				System.exit(1);
			}

		} catch (IOException e) {
			// TODO: handle exception
			System.out.println("Connection broken..");
			System.exit(1);
		}
	}

	public static void main (String[] args) {
		Client cli = new Client("localhost", 4002);
		int jobId = cli.sendJob("command.txt");
	}
	
}
